package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"iot-base/common/logger"
	"iot-base/common/serialdata"
	"net"
	"runtime"
	"time"
)

var tcpTimeOut = 500 * time.Millisecond
var serialTimeOut = 200 * time.Millisecond

func serialF() {
	listen, err := net.Listen("tcp", serialdata.SerialIP)
	if err != nil {
		fmt.Println("conn err:", err)
	}
	for {
		if conn, err := listen.Accept(); err == nil {
			TaskChan(conn)
		}
	}
}

func TaskChan(conn net.Conn) {
	fmt.Println("in serial chan!")
	fmt.Println("goruntine count", runtime.NumGoroutine())
	readBuffer := make([]byte, 2048)
	conn.SetReadDeadline(time.Now().Add(time.Second))
	n, err := conn.Read(readBuffer)
	if err != nil {
		fmt.Println("serial read err:", err)
		return
	}
	var dataFrame serialdata.DataFrame
	err = json.Unmarshal(readBuffer[:n], &dataFrame)
	if err != nil {
		fmt.Println("readBuffer:", string(readBuffer[:n]))
		fmt.Println("unMashal json serial data err:", err)
		return
	}
	switch dataFrame.Mod {
	case "serial":
		if _, ok := SerialDataChanManager[dataFrame.Config.Name]; !ok {
			SerialDataChanManager[dataFrame.Config.Name] = NewPriorityQueue()
			go serialChan(dataFrame.Config.Name)
		}
		switch dataFrame.Style {
		case "scan":
			SerialDataChanManager[dataFrame.Config.Name].PutNoWait(&QueueItem{
				Value: SerialTrans{
					SourceConn: &conn,
					Value:      dataFrame.Value,
					Config:     dataFrame.Config,
				},
				Priority: 2,
				JoinTime: time.Now(),
			})
		case "serve":
			SerialDataChanManager[dataFrame.Config.Name].PutNoWait(&QueueItem{
				Value: SerialTrans{
					SourceConn: &conn,
					Value:      dataFrame.Value,
					Config:     dataFrame.Config,
				},
				Priority: 1,
				JoinTime: time.Now(),
			})
		}
	case "tcp":
		if _, ok := TcpDataChanManager[dataFrame.Addr]; !ok {
			TcpDataChanManager[dataFrame.Addr] = NewPriorityQueue()
			go tcpChan(dataFrame.Addr)
		}
		switch dataFrame.Style {
		case "scan":
			TcpDataChanManager[dataFrame.Addr].PutNoWait(&QueueItem{
				Value: TcpTrans{
					&conn,
					dataFrame.Value,
					dataFrame.Addr,
				},
				Priority: 2,
				JoinTime: time.Now(),
			})
		case "serve":
			TcpDataChanManager[dataFrame.Addr].PutNoWait(&QueueItem{
				Value: TcpTrans{
					&conn,
					dataFrame.Value,
					dataFrame.Addr,
				},
				Priority: 1,
				JoinTime: time.Now(),
			})
		}
	}
}

func serialChan(name string) {
	for {
		if _, ok := SerialDataChanManager[name]; !ok {
			return
		}
		data := SerialDataChanManager[name].Get()
		if data == nil {
			LogErr("data err!", nil)
			continue
		}
		serialTarns, ok := data.Value.(SerialTrans)
		if !ok {
			LogErr("serialTrans data err!", nil)
			continue
		}
		dealSerialChan(serialTarns)
	}
}

func dealSerialChan(serialTarns SerialTrans) {
	sourceConn := serialTarns.GetSourceConn()
	port, err := serialTarns.GetTargetPort()
	defer func() {
		if sourceConn != nil {
			sourceConn.Close()
		}
		if port != nil {
			port.Close()
		}
	}()
	if err != nil {
		LogErr("open conn fail:", err)
		return
	}
	_, err = port.Write(serialTarns.Value)
	fmt.Println("send data:", serialTarns.Value)
	if err != nil {
		LogErr("write port fail:", err)
		return
	}
	buffer := make([]byte, 2048)
	go func() {
		for {
			n, err := port.Read(buffer)
			if err != nil {
				LogErr("read data err:", err)
				return
			}
			if n == 0 {
				continue
			}
			fmt.Println("re data:", buffer[:n])
			if _, err := sourceConn.Write(buffer[:n]); err != nil {
				LogErr("sourceConn write err:", err)
				return
			}
		}
	}()
	select {
	case <-time.After(serialTimeOut):
		fmt.Println("time out!")
		return
	}
}

func tcpChan(name string) {
	for {
		if _, ok := TcpDataChanManager[name]; !ok {
			return
		}
		data := TcpDataChanManager[name].Get()
		if data == nil {
			continue
		}
		tcpTarns, ok := data.Value.(TcpTrans)
		if !ok {
			LogErr("tcpTrans data err!", nil)
			continue
		}
		dealTcpChan(tcpTarns)
	}
}

func dealTcpChan(tcpTarns TcpTrans) {
	sourceConn := tcpTarns.GetSourceConn()
	targetConn, err := tcpTarns.GetTargetConn()
	defer func() {
		if sourceConn != nil {
			sourceConn.Close()
		}
		if targetConn != nil {
			targetConn.Close()
		}
		fmt.Println("this task end")
	}()
	if err != nil {
		LogErr("open port fail:", err)
		return
	}
	_, err = targetConn.Write(tcpTarns.Value)
	if err != nil {
		LogErr("open port fail:", err)
		return
	}
	fmt.Println("send data:", tcpTarns.Value)
	buffer := make([]byte, 2048)
	ReBuffer := make([]byte, 2048)
	go func() {
		for {
			err := targetConn.SetReadDeadline(time.Now().Add(tcpTimeOut))
			n, err := targetConn.Read(buffer)
			if err != nil {
				LogErr("read data err:", err)
				return
			}
			if n == 0 {
				continue
			}
			if bytes.Equal(ReBuffer[:n], buffer[:n]) {
				return
			}
			fmt.Println("re data:", buffer[:n])
			if _, err := sourceConn.Write(buffer[:n]); err != nil {
				LogErr("sourceConn write err:", err)
				return
			}
			ReBuffer = buffer
		}
	}()
	select {
	case <-time.After(tcpTimeOut):
		fmt.Println("time out!")
		return
	}
}

func LogErr(msg string, err error) {
	if err != nil {
		logger.Log.Error(msg + err.Error())
		return
	}
	logger.Log.Error(msg)
}
